/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Configuration;
using DaveSexton.DocProject.Configuration;
using VSLangProj80;
using DaveSexton.DocProject.Engine;
using System.ComponentModel;
using System.IO;
using System.Windows.Forms.Design;
using System.Drawing.Design;
using System.Reflection;
using System.Windows.Forms;
using DaveSexton.DocProject.Sandcastle.Configuration;
using DaveSexton.DocProject.Sandcastle.Resources;
using System.Collections.Generic;

namespace DaveSexton.DocProject.Sandcastle
{
	public class SandcastleBuildEngineProvider : BuildEngineProvider
	{
		#region Public Properties
		public static SandcastleSection Configuration
		{
			[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
			get
			{
				EnsureConfiguration();

				return sandcastleConfig;
			}
		}

		public static ProjectPathsElement ProjectPaths
		{
			[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
			get
			{
				return Configuration.ProjectPaths;
			}
		}

		public static PathsElement Paths
		{
			[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
			get
			{
				return Configuration.Paths;
			}
		}

		public static PresentationCollection Presentations
		{
			[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
			get
			{
				return Configuration.Presentations;
			}
		}

		public static Presentation DefaultPresentation
		{
			[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
			get
			{
				return Configuration.Presentations[Configuration.DefaultPresentation];
			}
			[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				Configuration.DefaultPresentation = value.Name;
			}
		}

		public static ConfigChangeElementCollection ConfigChanges
		{
			[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
			get
			{
				return Configuration.ConfigChanges;
			}
		}

		public static string DefaultPresentationFullPath
		{
			[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
			get
			{
				return Path.Combine(Paths.Presentation, DefaultPresentation.Path);
			}
		}

		[Category("Configuration"), DisplayName("Html Help Workshop"), Editor(typeof(SandcastleBuildEngineProvider.HtmlHelpWorkshopFileEditor), typeof(UITypeEditor)),
		Description("Full path and file name of the Microsoft Html Help Workshop compiler, hhc.exe.")]
		public string HtmlHelpWorkshopLocation
		{
			get
			{
				return htmlHelpWorkshopLocation ?? Paths.HtmlHelpWorkshop;
			}
			set
			{
				if (string.IsNullOrEmpty(value))
					throw new ArgumentException(Errors.NullOrEmpty);

				htmlHelpWorkshopLocation = value;
			}
		}

		[Category("Configuration"), DisplayName("Sandcastle"), Editor(typeof(SandcastleBuildEngineProvider.SandcastleFolderEditor), typeof(UITypeEditor)),
		Description("Full path to the directory where Sandcastle is installed.")]
		public string SandcastleInstallPath
		{
			get
			{
				return sandcastleInstallPath ?? Paths.Root;
			}
			set
			{
				if (string.IsNullOrEmpty(value))
					throw new ArgumentException(Errors.NullOrEmpty);

				sandcastleInstallPath = value;
			}
		}

		public override bool HasToolBars
		{
			get
			{
				return true;
			}
		}

		public override bool HasToolWindows
		{
			get
			{
				return true;
			}
		}
		#endregion

		#region Private / Protected
		protected override IEnumerable<ToolBar> ToolBarsInternal
		{
			get
			{
				if (toolBar == null)
					toolBar = new SandcastleToolBar(this);

				yield return toolBar;
			}
		}

		protected override IEnumerable<ToolWindow> ToolWindowsInternal
		{
			get
			{
				yield return TopicManagement.TopicExplorer.Instance;
				yield return TopicManagement.TopicFiltersToolWindow.Instance;
				yield return TopicManagement.TopicEditorToolWindow.Instance;
				yield return TopicManagement.TopicPropertiesToolWindow.Instance;
			}
		}

		protected override string CustomExternalSourcesAssemblyOrFileDialogFilter
		{
			get
			{
				return Text.ReflectionFileDialogFilter;
			}
		}

		private static SandcastleSection sandcastleConfig;

		private SandcastleToolBar toolBar;
		private string htmlHelpWorkshopLocation, sandcastleInstallPath;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="SandcastleBuildEngineProvider" /> class.
		/// </summary>
		public SandcastleBuildEngineProvider()
		{
		}
		#endregion

		#region Methods
		[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
		public static bool VerifySandcastleInstalled()
		{
			string dxroot = Paths.Root;

			return !string.IsNullOrEmpty(dxroot) && System.IO.Directory.Exists(dxroot);
		}

		[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
		private static void EnsureConfiguration()
		{
			if (sandcastleConfig == null)
			{
				sandcastleConfig = DocProjectEnvironment.GetConfigurationSection("sandcastle") as SandcastleSection;

				if (sandcastleConfig == null)
					throw new InvalidOperationException(Errors.MissingSandcastleConfigSection);
			}
		}

		public static bool IsProjectValid(IDocProject project)
		{
			if (project == null)
				throw new ArgumentNullException("project");

			return SandcastleBuildEngineProvider.Presentations.Contains(
				SandcastleProjectOptions.GetPresentationName(project));
		}

		public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
		{
			EnsureConfiguration();

			base.Initialize(name, config);
		}

		public override void Load()
		{
			// do nothing
		}

		public override void Unload()
		{
			// do nothing
		}

		public override void Verify()
		{
			if (!SandcastleBuildEngineProvider.VerifySandcastleInstalled())
				throw new InvalidOperationException(string.Format(System.Globalization.CultureInfo.CurrentCulture, Errors.SandcastleNotVerified, Environment.NewLine));
		}

		public override void CommitProviderSettings()
		{
			base.CommitProviderSettings();

			bool hasUpdates = false;

			if (htmlHelpWorkshopLocation != null)
			{
				Paths.HtmlHelpWorkshop = htmlHelpWorkshopLocation;
				htmlHelpWorkshopLocation = null;
				hasUpdates = true;
			}

			if (sandcastleInstallPath != null)
			{
				Paths.Root = sandcastleInstallPath;
				sandcastleInstallPath = null;
				hasUpdates = true;
			}

			if (hasUpdates)
				Paths.SaveChanges();
		}

		public override void CancelProviderSettings()
		{
			base.CancelProviderSettings();

			htmlHelpWorkshopLocation = null;
			sandcastleInstallPath = null;
		}

		public override bool CreatesBuildEngineOfType(Type type)
		{
			if (type == null)
				throw new ArgumentNullException("type");

			return type == typeof(SandcastleBuildEngine);
		}

		public override DaveSexton.DocProject.Engine.IBuildEngine CreateBuildEngine(IDocProject project)
		{
			SandcastleBuildEngine engine = new SandcastleBuildEngine(project);

			return engine;
		}

		public override DocProjectOptions CreateProjectOptions(IDocProject project)
		{
			SandcastleProjectOptions options = new SandcastleProjectOptions(project);

			string name = options.PresentationName;

			if (string.IsNullOrEmpty(name))
				throw new InvalidOperationException(string.Format(System.Globalization.CultureInfo.CurrentCulture, 
					Resources.Errors.MissingPresentationName, project.Name));

			SandcastleBuildEngineProvider.Presentations.EnsureExists(name);

			return options;
		}

		public override BuildSettings CreateBuildSettings(IBuildEngine engine)
		{
			if (engine == null)
				throw new ArgumentNullException("engine");

			if (!(engine is SandcastleBuildEngine))
				throw new ArgumentException(Errors.InvalidBuildEngineTypeSandcastle, "engine");

			return new SandcastleSettings(engine);
		}

		public override DaveSexton.DocProject.Wizards.Foundation.WizardStep CreateNewProjectWizardStep(IDocProject project)
		{
			ChoosePresentationWizardStep presentation = new ChoosePresentationWizardStep(project);
			ImportSettingsWizardStep settings = new ImportSettingsWizardStep(presentation);
			ChooseCompiledHelpWizardStep output = new ChooseCompiledHelpWizardStep(project, presentation);
			LocateCompilersWizardStep locateCompilers = new LocateCompilersWizardStep(project, output);
			CreateSharedContentWizardStep createSharedContent = new CreateSharedContentWizardStep(project, presentation);

			presentation.InsertBefore(settings)
				.InjectBefore(output)
				.InjectBefore(locateCompilers)
				.InjectBefore(createSharedContent);

			return presentation;
		}

		public override void NotifyNewProjectWizardCompleted(IDocProject project, 
			DaveSexton.DocProject.Wizards.Foundation.WizardController controller, bool succeeded)
		{
			if (succeeded && controller != null && controller.Data.ContainsKey("importResults"))
			{
				ICollection<string> messages = controller.Data["importResults"] as ICollection<string>;

				if (messages != null && messages.Count > 0)
				{
					System.Text.StringBuilder results = new System.Text.StringBuilder();

					results.AppendFormat(System.Globalization.CultureInfo.CurrentCulture, Resources.Text.ImportSucceeded, project.FilePath);
					results.AppendLine();
					results.AppendFormat("{0} messages(s)", messages.Count);
					results.AppendLine();
					results.AppendLine();

					foreach (string value in messages)
						results.AppendLine(value);

					using (ImportResultsDialog dialog = new ImportResultsDialog())
					{
						dialog.StartPosition = FormStartPosition.CenterParent;
						dialog.Results = results.ToString();
						dialog.ShowDialog(DocProjectEnvironment.MainWindow);
					}
				}
			}
		}

		protected internal virtual void ImportOptions(IDocProject fromProject, IDocProject toProject)
		{
			SandcastleProjectOptions.ImportOptions(fromProject, toProject, false);		// NOTE: Do not import external sources here.
		}

		#region Property Grid Reflection
		private bool ShouldSerializeHtmlHelpWorkshopLocation()
		{
			return !HtmlHelpWorkshopLocation.Equals(SandcastleBuildEngineProvider.Paths.HtmlHelpWorkshop, StringComparison.CurrentCultureIgnoreCase);
		}

		private void ResetHtmlHelpWorkshopLocation()
		{
			HtmlHelpWorkshopLocation = SandcastleBuildEngineProvider.Paths.HtmlHelpWorkshop;
		}

		private bool ShouldSerializeSandcastleInstallPath()
		{
			return !SandcastleInstallPath.Equals(SandcastleBuildEngineProvider.Paths.Root, StringComparison.CurrentCultureIgnoreCase);
		}

		private void ResetSandcastleInstallPath()
		{
			SandcastleInstallPath = SandcastleBuildEngineProvider.Paths.Root;
		}
		#endregion
		#endregion

		#region Nested
		private sealed class SandcastleFolderEditor : FolderNameEditor
		{
			protected override void InitializeDialog(FolderBrowser folderBrowser)
			{
				folderBrowser.Description = "Locate Sandcastle Installation";
				folderBrowser.Style = FolderBrowserStyles.RestrictToFilesystem | FolderBrowserStyles.ShowTextBox;
				folderBrowser.StartLocation = FolderBrowserFolder.MyComputer;

				base.InitializeDialog(folderBrowser);
			}
		}

		private sealed class HtmlHelpWorkshopFileEditor : FileNameEditor
		{
			protected override void InitializeDialog(System.Windows.Forms.OpenFileDialog openFileDialog)
			{
				base.InitializeDialog(openFileDialog);

				openFileDialog.Title = "Find Html Help Workshop";
				openFileDialog.InitialDirectory = Path.GetDirectoryName(SandcastleBuildEngineProvider.Paths.HtmlHelpWorkshop);
				openFileDialog.CheckFileExists = true;
				openFileDialog.Filter = "Html Help Workshop (hhc.exe)|hhc.exe|All Programs (*.exe)|*.exe";
			}
		}
		#endregion
	}
}
